require 'optparse'
require 'sqlite3'
require 'rubygems'
require 'active_record'
require 'mechanize'
require 'logger'
require 'sinatra'
require 'rails'
require 'json'

$options = {}
parser = OptionParser.new("", 24) do |opts|
  opts.banner = "\nScraper 1.0\nAuthor: Louis (Skype: louisprm)\n\n"
  
  opts.on("-p", "--port PORT", "PORT") do |v|
    $options[:input] = v
  end

  opts.on_tail('-h', '--help', 'Displays this help') do
		puts opts
    exit
	end
end

# Parse!
parser.parse!

# Options
$options[:port] ||= 3000

# Module
module Louis
  
  class ArgumentMissing < RuntimeError
    
  end

  class InvalidArgument < RuntimeError
    
  end

  class NotSupported < RuntimeError
    
  end


  # Class
  class Scrape
    def self.run(params)
      begin
        e = self.new(params)
        return e.send(:scrape)
      rescue ArgumentMissing, InvalidArgument, NotSupported => exception
        return { error: exception.message.strip }
      #rescue Exception => exception
      #  return { error: 'unknown error' }
      end      
    end
    private
    def initialize(params)
      @logger = Logger.new('log.log')

      @params = params.symbolize_keys

      @logger.info('Params ' + @params.to_s)
      @params[:results_url] ||= 'http://www.tma-3.com'

      raise ArgumentMissing, "target_county_ansi_code missing" if @params[:target_county_ansi_code].blank?
      raise ArgumentMissing, "target_url missing" if @params[:target_url].blank?
      raise ArgumentMissing, "target_record missing" if @params[:target_record].blank?
      raise ArgumentMissing, "target_year missing" if @params[:target_year].blank?
      raise ArgumentMissing, "target_record missing" if @params[:target_record].blank?

      @a = Mechanize.new
      @a.agent.http.verify_mode = OpenSSL::SSL::VERIFY_NONE
      @a.user_agent_alias = 'Windows Mozilla'
    end

    def scrape
      if @params[:target_url][/smcare.org/]
        results = scrape_smcare
      else
        raise NotSupported, "#{@params[:target_url]} not supported"
      end

      respond(results) # @todo: this should be done in the background
      return results
    end

    def scrape_smcare
      @logger.info('Start scraping smcare' + @params.to_json)

      # trang search input
      @a.get('http://www.smcare.org/apps/LandDocs/grantee_index.asp')
      params = {
        'txtDocumentNumber1' => @params[:target_year],
        'txtDocumentNumber2' => @params[:target_record],
        'iTabIndex' => '2',
        'sGrantorGrantee' => '0',
        'sDocNumber1' => @params[:target_year],
        'sDocNumber2' => @params[:target_record],
        'sLinePerPage' => '25',
        'hRegRange' => '0',
        'sPredefined' => 'yes'
      }

      # trang search result 1
      ps = @a.post('http://www.smcare.org/apps/LandDocs/result.asp', params, 'Content-Type' => 'application/x-www-form-urlencoded').parser
      params = {
        'iTabIndex' => '2',
        'iError' => '0',
        'sGrantorGrantee' => '0',
        'sDocNumber1' => @params[:target_year],
        'sDocNumber2' => @params[:target_record],
        'sLinePerPage' => '25',
        'sDocNumberID' => ps.css('input[name=sDocNumberID]').first.attributes['value'].text,
        'sRecDate' => ps.css('input[name=sRecDate]').first.attributes['value'].text,
        'sPcorExists' => '0',
        'hSortByName' => '0',
        'hRealNum' => '0',
        'hRegRange' => '0',
        'sPredefined' => 'yes'
      }
      
      # trang results 2 (tự động submit bằng js của trang trước)
      begin
        ps2 = @a.post('http://www.smcare.org/apps/LandDocs/titledocs.asp', params, 'Content-Type' => 'application/x-www-form-urlencoded').parser
      rescue Exception => ex
        return []
      end
      
      params = {
        'iTabIndex' => '2',
        'sGrantorGrantee' => '0',
        'sDocNumber1' => @params[:target_year],
        'sDocNumber2' => @params[:target_record],
        'sLinePerPage' => '25',
        'sDocNumberID' => ps.css('input[name=sDocNumberID]').first.attributes['value'].text,
        'sRecDate' => ps.css('input[name=sRecDate]').first.attributes['value'].text,
        'sPcorExists' => '0',
        'sPredefined' => 'yes',
        'sTitleDocID' => ps2.css('a[oncontextmenu="return false;"]').select{|a| a.text[/view grantors\/grantee/i]}.first.attributes['href'].value[/[0-9]+/],
        'hRegRange' => '0'
      }
      
      # Click vào link View Grantor/Grantee
      ps3 = @a.post('http://www.smcare.org/apps/LandDocs/gg.asp', params, 'Content-Type' => 'application/x-www-form-urlencoded').parser
      
      results = {
        'record #' => "#{@params[:target_year]}-#{@params[:target_record]}",
        'record date' => ps2.css('font.maintext').text[/(?<=Recording Date: )[0-9]+\/[0-9]+\/[0-9]+/],
        'document type' => ps2.css('a[oncontextmenu="return false;"]').select{|a| a.text[/view grantors\/grantee/i]}.first.parent.previous_element.previous_element.previous_element.text.strip,
        'pages' => 1, # @todo here
        'parcel #' => '',
        'grantors' => ps3.css('table[width="550"]').select{|e| e.css('tr:first-child').first.text[/Grantors/] }.first.css('tr > td[width="60%"]').map{|td| td.text.strip },
        'grantees' => ps3.css('table[width="550"]').select{|e| e.css('tr:first-child').first.text[/Grantees/] }.first.css('tr > td[width="60%"]').map{|td| td.text.strip }
      }

      @logger.info("Results: " + results.to_json)

      return results
    end

    def respond(results)
      #@a.post(@params[:results_url], results, 'Content-Type' => 'application/x-www-form-urlencoded')
      #@logger.info("Posted to #{@params[:results_url]}")
    end
  end
end

# trap Ctrl-C
# trap("SIGINT") { throw :ctrl_c }

# Sinatra
set :port, $options[:port]
set :bind, '0.0.0.0'
set :server, 'webrick'

get '/form' do
  erb :form
end

get '/' do 
  content_type :json

  results = Louis::Scrape.run( params )
  
  # render JSON
  results.to_json
end

post '/' do 
  content_type :json

  results = Louis::Scrape.run( params )
  
  # render JSON
  results.to_json
end

